"""StatefulSet资源Markdown写入器模块"""

from typing import Dict, Any, List
import yaml
from src.writers.base import Writer
from src.utils.markdown_builder import MarkdownBuilder

class StatefulSetWriter(Writer):
    """
    StatefulSet资源Markdown写入器
    负责将提取的StatefulSet资源信息写入Markdown文件
    """
    
    def write(self, data: Dict[str, Any], output_path: str) -> None:
        """
        将提取的StatefulSet信息写入Markdown
        
        Args:
            data: 提取的StatefulSet信息
            output_path: 输出文件路径
        """
        if not data or data.get("kind") != "StatefulSet":
            self.logger.warning(f"无效的StatefulSet数据: {data.get('name', '未知')}")
            return
        
        # 创建Markdown构建器
        md = self.create_markdown_builder()
        
        # 收集节标题，用于生成目录
        sections = ["基本信息", "副本配置", "更新策略", "容器", "存储", "状态"]
        
        # 标题
        md.header(f"StatefulSet: {data.get('name', '未知')}", 1)
        
        # 命名空间
        md.bold("命名空间:").text(f" {data.get('namespace', 'default')}").newline(2)
        
        # 目录
        if len(sections) > 3:  # 只有当节较多时才添加目录
            md.toc(sections)
        
        # 基本信息
        self._write_basic_info(md, data)
        
        # 副本配置与Pod管理策略
        self._write_replica_config(md, data)
        
        # 更新策略
        self._write_update_strategy(md, data)
        
        # 容器
        self._write_containers(md, data)
        
        # 存储配置
        self._write_storage(md, data)
        
        # 状态
        self._write_status(md, data)
        
        # 生成Markdown文件
        self.write_markdown(md, output_path)
    
    def _write_basic_info(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入基本信息
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("基本信息", 2)
        
        # 基本元数据表
        basic_info = {
            "名称": data.get("name", ""),
            "命名空间": data.get("namespace", "default"),
            "创建时间": data.get("creation_timestamp", ""),
            "服务名称": data.get("service_name", "")
        }
        
        md.dict_table(basic_info)
        
        # 标签和选择器
        if data.get("labels"):
            md.header("标签", 3)
            md.dict_table(data.get("labels", {}))
        
        if data.get("annotations"):
            md.header("注解", 3)
            md.dict_table(data.get("annotations", {}))
            
        # 选择器
        if data.get("selector"):
            md.header("选择器", 3)
            md.dict_table(data.get("selector", {}).get("match_labels", {}))
            
            # 如果有match_expressions
            match_expressions = data.get("selector", {}).get("match_expressions", [])
            if match_expressions:
                md.header("选择器表达式", 4)
                
                headers = ["键", "操作符", "值"]
                rows = []
                
                for expr in match_expressions:
                    key = expr.get("key", "")
                    operator = expr.get("operator", "")
                    values = expr.get("values", [])
                    
                    # 翻译operator为更友好的说明
                    operator_map = {
                        "In": "在列表中",
                        "NotIn": "不在列表中",
                        "Exists": "存在",
                        "DoesNotExist": "不存在"
                    }
                    operator = operator_map.get(operator, operator)
                    
                    rows.append([key, operator, ", ".join(values)])
                
                md.table(headers, rows)
    
    def _write_replica_config(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入副本配置和Pod管理策略
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("副本配置", 2)
        
        # 副本配置
        replica_config = {
            "副本数": data.get("replicas", 1)
        }
        
        # Pod管理策略
        pod_management_policy = data.get("pod_management_policy", "OrderedReady")
        policy_map = {
            "OrderedReady": "有序创建 (OrderedReady)",
            "Parallel": "并行创建 (Parallel)"
        }
        replica_config["Pod管理策略"] = policy_map.get(pod_management_policy, pod_management_policy)
        
        # 服务名称
        if data.get("service_name"):
            replica_config["服务名称"] = data.get("service_name", "")
            md.paragraph("StatefulSet使用此服务名称为每个Pod生成稳定的DNS记录")
        
        # 修订历史限制
        if "revision_history_limit" in data:
            replica_config["修订历史限制"] = data.get("revision_history_limit", 10)
        
        md.dict_table(replica_config)
        
        # 添加Pod标识描述
        md.header("Pod标识", 3)
        md.paragraph(f"Pod将按照{data.get('name')}-0, {data.get('name')}-1, ...的方式命名")
        
        # 如果有服务名，解释DNS记录
        if data.get("service_name"):
            service_name = data.get("service_name")
            namespace = data.get("namespace", "default")
            md.paragraph("每个Pod将获得稳定的DNS记录，格式如下:")
            md.code(f"{data.get('name')}-{{0..N-1}}.{service_name}.{namespace}.svc.cluster.local")
            md.paragraph("其中N为副本数量")
    
    def _write_update_strategy(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入更新策略
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("更新策略", 2)
        
        update_strategy = data.get("update_strategy", {})
        if not update_strategy:
            md.paragraph("未指定更新策略，使用默认配置")
            return
        
        strategy_type = update_strategy.get("type", "RollingUpdate")
        
        # 翻译策略类型为更友好的说明
        strategy_map = {
            "RollingUpdate": "滚动更新",
            "OnDelete": "删除时更新"
        }
        strategy_type_display = strategy_map.get(strategy_type, strategy_type)
        
        md.paragraph(f"更新策略类型: **{strategy_type_display}**")
        
        # 滚动更新设置
        if strategy_type == "RollingUpdate" and "rolling_update" in update_strategy:
            rolling_update = update_strategy.get("rolling_update", {})
            
            if "partition" in rolling_update:
                partition = rolling_update.get("partition", 0)
                md.paragraph(f"分区更新设置: 索引大于等于 **{partition}** 的Pod将被更新")
                
                if partition > 0:
                    md.paragraph(f"注意: 当前设置将只更新{data.get('name')}-{partition}及更高索引的Pod，" +
                                f"索引为0至{partition-1}的Pod保持不变")
    
    def _write_containers(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入容器信息
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("容器", 2)
        
        # 获取容器信息
        pod_spec = data.get("template", {}).get("spec", {})
        containers = pod_spec.get("containers", [])
        
        if not containers:
            md.paragraph("未定义容器")
            return
        
        # 遍历每个容器
        for i, container in enumerate(containers):
            container_name = container.get("name", f"container-{i+1}")
            md.header(f"容器 {i+1}: {container_name}", 3)
            
            # 基本容器信息
            with md.list() as lst:
                lst.item(f"**镜像:** {container.get('image', '未指定')}")
                
                if "image_pull_policy" in container:
                    lst.item(f"**镜像拉取策略:** {container.get('image_pull_policy')}")
                    
                if "command" in container:
                    command = " ".join(container.get("command", []))
                    lst.item(f"**命令:** `{command}`")
                    
                if "args" in container:
                    args = " ".join(container.get("args", []))
                    lst.item(f"**参数:** `{args}`")
            
            # 端口
            if container.get("ports"):
                md.header("端口", 4)
                
                headers = ["名称", "容器端口", "协议"]
                rows = []
                
                for port in container.get("ports", []):
                    rows.append([
                        port.get("name", ""),
                        str(port.get("container_port", "")),
                        port.get("protocol", "TCP")
                    ])
                
                md.table(headers, rows)
            
            # 环境变量
            if container.get("env"):
                md.header("环境变量", 4)
                
                headers = ["名称", "值", "来源"]
                rows = []
                
                for env in container.get("env", []):
                    name = env.get("name", "")
                    value = env.get("value", "")
                    value_from = ""
                    
                    if "value_from" in env:
                        value_from_dict = env.get("value_from", {})
                        if "configMapKeyRef" in value_from_dict:
                            cm_ref = value_from_dict.get("configMapKeyRef", {})
                            value_from = f"ConfigMap: {cm_ref.get('name', '')}.{cm_ref.get('key', '')}"
                        elif "secretKeyRef" in value_from_dict:
                            secret_ref = value_from_dict.get("secretKeyRef", {})
                            value_from = f"Secret: {secret_ref.get('name', '')}.{secret_ref.get('key', '')}"
                        elif "fieldRef" in value_from_dict:
                            field_ref = value_from_dict.get("fieldRef", {})
                            value_from = f"Field: {field_ref.get('field_path', '')}"
                        elif "resourceFieldRef" in value_from_dict:
                            res_ref = value_from_dict.get("resourceFieldRef", {})
                            value_from = f"Resource: {res_ref.get('resource', '')}"
                    
                    rows.append([name, value, value_from])
                
                md.table(headers, rows)
                
            # 资源限制
            if container.get("resources"):
                md.header("资源配置", 4)
                
                resources = container.get("resources", {})
                requests = resources.get("requests", {})
                limits = resources.get("limits", {})
                
                if requests:
                    md.bold("请求:").newline()
                    
                    with md.list() as lst:
                        for resource_type, value in requests.items():
                            lst.item(f"{resource_type}: {value}")
                    
                    md.newline()
                
                if limits:
                    md.bold("限制:").newline()
                    
                    with md.list() as lst:
                        for resource_type, value in limits.items():
                            lst.item(f"{resource_type}: {value}")
                    
                    md.newline()
            
            # 健康检查
            if container.get("liveness_probe"):
                md.header("存活探针", 4)
                self._write_probe(md, container.get("liveness_probe", {}))
            
            if container.get("readiness_probe"):
                md.header("就绪探针", 4)
                self._write_probe(md, container.get("readiness_probe", {}))
                
            if container.get("startup_probe"):
                md.header("启动探针", 4)
                self._write_probe(md, container.get("startup_probe", {}))
            
            # 卷挂载
            if container.get("volume_mounts"):
                md.header("卷挂载", 4)
                
                headers = ["名称", "挂载路径", "只读", "子路径"]
                rows = []
                
                for mount in container.get("volume_mounts", []):
                    name = mount.get("name", "")
                    path = mount.get("mount_path", "")
                    read_only = "是" if mount.get("read_only", False) else "否"
                    sub_path = mount.get("sub_path", "")
                    
                    rows.append([name, path, read_only, sub_path])
                
                md.table(headers, rows)
    
    def _write_probe(self, md: MarkdownBuilder, probe: Dict[str, Any]) -> None:
        """
        写入探针信息
        
        Args:
            md: Markdown构建器
            probe: 探针信息字典
        """
        with md.list() as lst:
            # 初始延迟
            if "initial_delay_seconds" in probe:
                lst.item(f"初始延迟: {probe.get('initial_delay_seconds')}秒")
            
            # 超时
            if "timeout_seconds" in probe:
                lst.item(f"超时: {probe.get('timeout_seconds')}秒")
            
            # 周期
            if "period_seconds" in probe:
                lst.item(f"周期: {probe.get('period_seconds')}秒")
            
            # 成功阈值
            if "success_threshold" in probe:
                lst.item(f"成功阈值: {probe.get('success_threshold')}")
            
            # 失败阈值
            if "failure_threshold" in probe:
                lst.item(f"失败阈值: {probe.get('failure_threshold')}")
            
            # 探针类型和参数
            if "http_get" in probe:
                http_get = probe.get("http_get", {})
                path = http_get.get("path", "/")
                port = http_get.get("port", 80)
                lst.item(f"HTTP GET 探针: {path} (端口: {port})")
            elif "tcp_socket" in probe:
                tcp_socket = probe.get("tcp_socket", {})
                port = tcp_socket.get("port", 80)
                lst.item(f"TCP Socket 探针: 端口 {port}")
            elif "exec" in probe:
                exec_probe = probe.get("exec", {})
                command = exec_probe.get("command", [])
                if command:
                    cmd_str = " ".join(command)
                    lst.item(f"Exec 探针: `{cmd_str}`")
    
    def _write_storage(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入存储配置
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("存储", 2)
        
        # 获取存储卷
        pod_spec = data.get("template", {}).get("spec", {})
        volumes = pod_spec.get("volumes", [])
        
        # 获取卷声明模板
        volume_claim_templates = data.get("volume_claim_templates", [])
        
        if not volumes and not volume_claim_templates:
            md.paragraph("未定义存储卷或卷声明模板")
            return
        
        # 先写入卷声明模板（这是StatefulSet的主要存储特性）
        if volume_claim_templates:
            md.header("持久卷声明模板", 3)
            md.paragraph("这些PVC模板将为每个Pod实例创建独立的持久存储:")
            md.newline()
            
            for i, pvc_template in enumerate(volume_claim_templates):
                pvc_name = pvc_template.get("metadata", {}).get("name", f"volume-claim-{i+1}")
                md.header(f"PVC模板 {i+1}: {pvc_name}", 4)
                md.newline()
                
                # PVC基本信息
                pvc_spec = pvc_template.get("spec", {})
                
                # 访问模式
                access_modes = pvc_spec.get("access_modes", [])
                access_modes_str = ", ".join(access_modes) if access_modes else "未指定"
                
                # 存储类
                storage_class = pvc_spec.get("storage_class_name", "默认")
                
                # 存储大小
                storage_size = pvc_spec.get("resources", {}).get("requests", {}).get("storage", "未指定")
                
                # 卷模式
                volume_mode = pvc_spec.get("volume_mode", "Filesystem")
                
                pvc_info = {
                    "名称": pvc_name,
                    "访问模式": access_modes_str,
                    "存储类": storage_class,
                    "存储大小": storage_size,
                    "卷模式": volume_mode
                }
                
                md.dict_table(pvc_info)
                md.newline()
                
                # 说明此PVC如何在每个Pod中使用
                md.paragraph(f"对于每个Pod副本，将创建名为`{pvc_name}-{{Pod名称}}`的PVC实例")
                md.newline()
        
        # 然后写入普通卷
        if volumes:
            md.header("普通存储卷", 3)
            md.paragraph("这些存储卷在所有Pod副本之间共享同一配置:")
            md.newline()
            
            # 遍历每个卷
            for i, volume in enumerate(volumes):
                volume_name = volume.get("name", f"volume-{i+1}")
                md.header(f"卷 {i+1}: {volume_name}", 4)
                md.newline()
                
                # 确定卷类型并格式化
                if "config_map" in volume:
                    config_map = volume.get("config_map", {})
                    md.bold("类型:").text(" ConfigMap").newline(2)
                    md.bold("ConfigMap名称:").text(f" {config_map.get('name', '')}").newline(2)
                    
                    if "items" in config_map:
                        md.bold("配置项:").newline()
                        
                        with md.list() as lst:
                            for item in config_map.get("items", []):
                                key = item.get("key", "")
                                path = item.get("path", "")
                                lst.item(f"{key} -> {path}")
                        md.newline()
                
                elif "secret" in volume:
                    secret = volume.get("secret", {})
                    md.bold("类型:").text(" Secret").newline(2)
                    md.bold("Secret名称:").text(f" {secret.get('name', '')}").newline(2)
                    
                    if "items" in secret:
                        md.bold("配置项:").newline()
                        
                        with md.list() as lst:
                            for item in secret.get("items", []):
                                key = item.get("key", "")
                                path = item.get("path", "")
                                lst.item(f"{key} -> {path}")
                        md.newline()
                
                elif "empty_dir" in volume:
                    empty_dir = volume.get("empty_dir", {})
                    md.bold("类型:").text(" emptyDir").newline(2)
                    
                    if "medium" in empty_dir:
                        md.bold("存储介质:").text(f" {empty_dir.get('medium', 'Memory')}").newline(2)
                    
                    if "size_limit" in empty_dir:
                        md.bold("大小限制:").text(f" {empty_dir.get('size_limit', '')}").newline(2)
                
                elif "host_path" in volume:
                    host_path = volume.get("host_path", {})
                    md.bold("类型:").text(" hostPath").newline(2)
                    md.bold("路径:").text(f" {host_path.get('path', '')}").newline(2)
                    
                    if "type" in host_path:
                        type_map = {
                            "": "未指定",
                            "DirectoryOrCreate": "目录或创建",
                            "Directory": "目录",
                            "FileOrCreate": "文件或创建",
                            "File": "文件",
                            "Socket": "套接字",
                            "CharDevice": "字符设备",
                            "BlockDevice": "块设备"
                        }
                        type_value = host_path.get("type", "")
                        md.bold("类型:").text(f" {type_map.get(type_value, type_value)}").newline(2)
                
                else:
                    # 处理其他可能的卷类型
                    volume_type = next(iter(volume.keys()), "unknown")
                    if volume_type != "name":
                        md.bold("类型:").text(f" {volume_type}").newline(2)
                        md.bold("详细信息:").newline()
                        
                        with md.code_block("yaml"):
                            md.text(yaml.dump(volume, default_flow_style=False))
                        md.newline()
                
                # 在每个卷之后添加额外的空行
                md.newline()
    
    def _write_status(self, md: MarkdownBuilder, data: Dict[str, Any]) -> None:
        """
        写入状态信息
        
        Args:
            md: Markdown构建器
            data: StatefulSet数据
        """
        md.header("状态", 2)
        
        status = data.get("status", {})
        if not status:
            md.paragraph("未提供状态信息")
            return
        
        # 创建状态信息表
        status_info = {}
        
        # 副本数统计
        status_info["当前副本数"] = status.get("current_replicas", 0)
        status_info["就绪副本数"] = status.get("ready_replicas", 0)
        status_info["期望副本数"] = status.get("replicas", 0)
        
        # 更新信息
        if "update_revision" in status:
            status_info["当前更新版本"] = status.get("update_revision", "")
        if "current_revision" in status:
            status_info["当前基准版本"] = status.get("current_revision", "")
        
        # 更新相关统计
        if "updated_replicas" in status:
            status_info["已更新副本数"] = status.get("updated_replicas", 0)
        
        # 修订版本信息
        md.dict_table(status_info)
        
        # 显示每个Pod的创建状态
        replicas = data.get("replicas", 0)
        if replicas > 0:
            md.header("Pod状态", 3)
            md.paragraph(f"StatefulSet将按顺序创建和更新{replicas}个Pod:")
            
            # 我们不知道确切的Pod状态，但可以描述StatefulSet的Pod创建和更新顺序
            md.paragraph("StatefulSet遵循以下规则创建和更新Pod:")
            with md.list() as lst:
                lst.item(f"Pod将按照从0到{replicas-1}的顺序**创建**")
                lst.item("在部署过程中，下一个Pod仅在前一个Pod已经就绪后才会创建")
                
                update_strategy = data.get("update_strategy", {})
                strategy_type = update_strategy.get("type", "RollingUpdate")
                
                if strategy_type == "RollingUpdate":
                    partition = update_strategy.get("rolling_update", {}).get("partition", 0)
                    if partition > 0:
                        lst.item(f"当更新时，只有序号 >= {partition} 的Pod会被更新")
                    else:
                        lst.item("更新时，Pod将按照从高到低的顺序（从{replicas-1}到0）进行更新")
                elif strategy_type == "OnDelete":
                    lst.item("当使用OnDelete更新策略时，Pod只有在被手动删除后才会更新")